﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// this is used to detect edges
    /// </summary>
    public class EdgeDetectConvolution : BaseImageFilter
    {
        protected short m_nType = 0;
        protected byte m_nThreshold = 0;

        /// <summary>
        /// default constructor
        /// </summary>
        public EdgeDetectConvolution()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="EdgeDetectConvolution"/> class.
        /// </summary>
        /// <param name="_nType">Type of the _n.</param>
        /// <param name="_nThreshold">The _n threshold.</param>
        public EdgeDetectConvolution(short _nType, byte _nThreshold)
        {
            m_nType = _nType;
            m_nThreshold = _nThreshold;
        }

        /// <summary>
        /// this is used by clone to create a deep copy
        /// </summary>
        /// <param name="_edgeDetectConvolution"></param>
        internal EdgeDetectConvolution(EdgeDetectConvolution _edgeDetectConvolution)
        {
            this.m_nType = _edgeDetectConvolution.m_nType;
            this.m_nThreshold = _edgeDetectConvolution.m_nThreshold;
        }

        /// <summary>
        /// Gets or sets the type
        /// </summary>
        public short Type
        {
            get { return m_nType; }
            set { m_nType = value; }
        }

        /// <summary>
        /// Gets or sets the threshold value
        /// </summary>
        public byte Threshold
        {
            get { return m_nThreshold; }
            set { m_nThreshold = value; }
        }

        /// <summary>
        /// edge detection convolution filter
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            CConvMatrix matrix = new CConvMatrix();

            UnsafeBitmap bitmap = _bitmap;
            // I need to make a copy of this bitmap BEFORE I alter it 80)
            UnsafeBitmap bTemp = (UnsafeBitmap)bitmap.Clone();
        
            switch (m_nType)
            {
                case (short)EdgeDetectMode.EDGE_DETECT_SOBEL:
                    matrix.SetAll(0);
                    matrix.TopLeft = matrix.TopRight = 1;
                    matrix.BottomLeft = matrix.BottomRight = -1;
                    matrix.TopMid = 2;
                    matrix.BottomMid = -2;
                    matrix.Offset = 0;
                    break;

                case (short)EdgeDetectMode.EDGE_DETECT_PREWITT:
                    matrix.SetAll(0);
                    matrix.BottomLeft = matrix.BottomMid = matrix.BottomRight = -1;
                    matrix.TopLeft = matrix.TopMid = matrix.TopRight = 1;
                    matrix.Offset = 0;
                    break;

                case (short)EdgeDetectMode.EDGE_DETECT_KIRSH:
                    matrix.SetAll(-3);
                    matrix.Pixel = 0;
                    matrix.BottomLeft = matrix.BottomMid = matrix.BottomRight = 5;
                    matrix.Offset = 0;
                    break;
            }

            new Convolution3x3(matrix).Execute(bitmap);

            // GDI+ still lies to us - the return format is BGR, NOT RGB.
            /*BitmapData bmData = bitmap.BitmapData; //bitmap.BitmapData; //bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            BitmapData bmData2 = bTemp.BitmapData; // bTemp.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

            int stride = bmData.Stride;
            IntPtr Scan0 = bmData.Scan0;
            IntPtr Scan02 = bmData2.Scan0;

            int nHeight = bitmap.Height;
            int nWidth = bitmap.Width;

            unsafe
            {
                byte* p = (byte*)(void*)Scan0;
                byte* p2 = (byte*)(void*)Scan02;

                int nOffset = stride - bitmap.Width * 3;
                //int nWidth = bitmap.Width * 3;

                int nPixel = 0;

                for (int y = 0; y < nHeight; ++y)
                {
                    for (int x = 0; x < nWidth; ++x)
                    {
                        nPixel = (int)Math.Sqrt((p[0] * p[0]) + (p2[0] * p2[0]));
                        if (nPixel < m_nThreshold) nPixel = m_nThreshold;
                        if (nPixel > 255) nPixel = 255;
                        p[0] = (byte)nPixel;
                        ++p;
                        ++p2;
                    }
                    p += nOffset;
                    p2 += nOffset;
                }
            }*/

            bTemp.Dispose(); // bTemp.UnlockBits(bmData2);
            return _bitmap;
        }

        /// <summary>
        /// used to create a deep copy
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new EdgeDetectConvolution(this);
        }
    }
}
